package com.zee.common.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.zee.admin.model.excel.SysUserExcel;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.List;

/**
 * EasyExcel工具类
 *
 * @author Mark LinZee
 * @email LinZee666@163.com
 **/
public class EasyExcelUtil {
    /**
     * 简单写excel输出浏览器，数据量不大的情况下可以使用（5000以内，具体也要看实际情况）
     *
     * @param response   响应信息
     * @param filename   文件名
     * @param sourceList 导出数据集合
     * @param sheetName  sheel名称
     * @param clazz      类字节码
     */
    public static void simpleWrite(HttpServletResponse response, String filename,
                                   Collection<?> sourceList, String sheetName, Class<?> clazz) {
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            filename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + filename + "." + ExcelTypeEnum.XLSX);

            EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(sourceList);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 分页数据重复写excel（同一个sheet）并输出浏览器，数据类需要继承EasyExcelRepeatWritePages抽象类，
     * 传进repeatWritePages参数的好处是可以写匿名内部类（因为每个地方的server不同，不用创建那么多类）
     * 应用示例，参考SysLogOperationController->export()方法
     *
     * @param response         响应信息
     * @param filename         文件名
     * @param sheetName        sheel名称
     * @param clazz            类字节码
     * @param repeatWritePages 模板的数据类
     */
    public static void repeatWrite(HttpServletResponse response, String filename,
                                   String sheetName, Class<?> clazz, EasyExcelRepeatWritePages<?> repeatWritePages) {
        ExcelWriter excelWriter = null;
        // 写到同一个sheet，需要指定写用哪个class去写
        try {

            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            filename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + filename + "." + ExcelTypeEnum.XLSX);

            excelWriter = EasyExcel.write(response.getOutputStream(), clazz).build();

            // 这里注意 如果同一个sheet只要创建一次
            WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();

            // 根据数据库分页的总的页数去查询数据
            for (int i = 1; i <= repeatWritePages.getPageSize(); i++) {
                // 查询每一页的数据并写入sheet
                List<?> data = repeatWritePages.getCurrentPageData(i);
                excelWriter.write(data, writeSheet);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 千万别忘记finish 会帮忙关闭流，不关闭无法输出到response
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    /**
     * 简单读取excel
     *
     * @param inputStream  输入流
     * @param clazz        字节码
     * @param readListener 模板的读取类
     */
    public static void simpleRead(InputStream inputStream, Class<?> clazz, ReadListener<?> readListener) {
        // 指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(inputStream, clazz, readListener).sheet().doRead();
    }

    public static void main(String[] args) {
        /************读取excel调用示例***********/
        simpleReadDemo();
    }


    /**
     * 简单读excel示例
     */
    private static void simpleReadDemo() {
        File file = new File("C:\\Users\\Administrator\\Desktop\\export_1676546978612.XLSX");
        FileInputStream fileInputStream = null;

        try {
            // 读取文件输入流
            fileInputStream = new FileInputStream(file);
            // 调用工具类方法，直接实现ReadListener的匿名内部类
            EasyExcelUtil.simpleRead(fileInputStream, SysUserExcel.class, new ReadListener<SysUserExcel>() {
                /**
                 * 单次缓存的数据量
                 */
                public static final int BATCH_COUNT = 1000;
                /**
                 *临时存储
                 */
                private List<SysUserExcel> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                /**
                 * 这个每一条数据解析都会来调用
                 * @param data
                 * @param context
                 */
                @Override
                public void invoke(SysUserExcel data, AnalysisContext context) {
                    cachedDataList.add(data);
                    System.out.println("解析到一条数据：" + data);
                    // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
                    if (cachedDataList.size() >= BATCH_COUNT) {
                        saveData();
                        // 存储完成清理 list
                        cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                    }
                }

                /**
                 * 所有数据解析完成了 都会来调用
                 * @param context
                 */
                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    // 这里也要保存数据，确保最后遗留的数据也存储到数据库
                    saveData();
                }

                /**
                 * 存储数据库操作
                 */
                private void saveData() {
                    System.out.println("当前list中的数据：" + cachedDataList.size());
                    System.out.println("存储数据库成功...");
                }
            });
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
        }
    }

    /**
     * 多次重复写excel输出浏览器示例
     */
    //@GetMapping("export2")
    //@ApiOperation("测试导出")
    //public void export2(@RequestParam HashMap<String, Object> params, HttpServletResponse response) {
    //    String filename = "export_" + System.currentTimeMillis();
    //    EasyExcelUtil.repeatWrite(response, filename, "用户数据",
    //            SysUserExcel.class, new EasyExcelRepeatWritePages<SysUserExcel>() {
    //                @Override
    //                public int getPageSize() {
    //                    // 根据params查询条件查出符合的数据
    //                    int pageCount = sysUserService.pageCount(params);
    //                    return pageCount;
    //                }
    //
    //                @Override
    //                public List<SysUserExcel> getCurrentPageData(int page) {
    //                    // 根据params查询条件查出符合的数据
    //                    Page<SysUserVO> pages = sysUserService.page(params);
    //                    return ConvertUtil.sourceToTarget(pages.getRecords(), SysUserExcel.class);
    //                }
    //            });
    //}
}
